# -*- coding: utf-8 -*-
from MediaCollection.Database import Database
from MediaCollection.Audio.Track import Track
from Exceptions.LibraryException import LibraryException

"""
Die Cd-Klasse repräsentiert eine CD mit allen in der Datenbank gespeicherten 
Attributen. Über ein Objekt dieser Klasse können neue Einträge in die Datenbank 
eingefügt werden, im Gegenzug aber auch über die Id des Eintrags in der 
Datenbank die entsprechenden Informationen in das Objekt eingelesen werden.

@author: Philipp Dermitzel
@date: 2011-04-01
@version: 1.5.1
"""
class Cd(object):
    
    """
    ----------------------------------------------------------------------------
    Konstruktor
    ----------------------------------------------------------------------------
    """
    
    """
    Der  Konstruktor. Erstellt das Objekt und liest, falls eine ID übergeben 
    wird, die entsprechenden Daten aus der Datenbank ein.
    @param id: Wird eine ID übergeben, so werden die Daten der entsprechenden CD
        direkt eingelesen.
    @type id: int
    @param name: Wird ein Name und ein Artist übergeben, so werden die Daten der
        entsprechenden CD direkt eingelesen.
    @type name: String
    @param artist: Wird ein Name und ein Artist übergeben, so werden die Daten 
        der entsprechenden CD direkt eingelesen.
    @type artist: int
    """
    def __init__(self, id = None, name = None, artist = None): 
        """
        Speichert alle Informationen der CD. Ist über C(getData()) abrufbar.
        @type: Dictionary
        """
        self.__cdData = {
            'id' : None,
            'name' : None,
            'artist' : None,
            'year' : None,
            'imgPath' : None,
            'mbId' : None
        }
    
        """
        Speichert alle Genres, die der CD zugeordnet sind. Sind über 
        C(getGenres()) abrufbar. Neue Genres werden über C(addGenre()) 
        hinzugefügt. Die Zugehörigkeit kann über C(hasGenre()) abgefragt werden.
        @type: Array
        """
        self.__genres = [];
        
        if id is not None:
            self.__cdData['id'] = id
            self.getDataFromDb()
        elif (name is not None and artist is not None):
            self.__cdData['name'] = name
            self.__cdData['artist'] = artist
            self.getDataFromDb()
    
    """
    ----------------------------------------------------------------------------
    Getter und Setter
    ----------------------------------------------------------------------------
    """
        
    """
    Setzt die Attribute der CD um diese später erfolgreich in die Datenbank 
    einfügen zu können. Dafür sollte das übergebene Dictionary C(dataDict) alle 
    eben dort beschriebenen Informationen enthalten.    
    @param dataDict: Alle benötigten Informationen zur CD. Die momentan 
        genutzten Felder sind: id, name, artist (DB-ID), year, imgPath und mbId 
        (die MusicBrainz-Id).
    @type dataDict: Dictionary
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Cd
    """
    def setData(self, dataDict):
        if 'id' in dataDict:
            self.__cdData['id'] = dataDict['id']
        if 'name' in dataDict:
            self.__cdData['name'] = dataDict['name']
        if 'artist' in dataDict:
            self.__cdData['artist'] = dataDict['artist']
        if 'year' in dataDict:
            self.__cdData['year'] = dataDict['year']
        if 'imgPath' in dataDict:
            self.__cdData['imgPath'] = dataDict['imgPath']
        if 'mbId' in dataDict:
            self.__cdData['mbId'] = dataDict['mbId']
        return self
    
    """
    Setzt ein einzelnen Attribut der CD. Die momentan genutzten Felder sind: 
    id, name, artist (DB-ID), year, imgPath und mbId (die MusicBrainz-Id).
    @param key: Der Schlüssel.
    @type key: String
    @param value: Der zu setzende Wert.
    @type value: int oder String
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Cd
    """    
    def setValue(self, key, value):
        if key == "id":
            self.__cdData['id'] = value
        elif key == "name":
            self.__cdData['name'] = value
        elif key == "artist":
            self.__cdData['artist'] = value
        elif key == "year":
            self.__cdData['year'] = value
        elif key == "imgPath":
            self.__cdData['imgPath'] = value
        elif key == "mbId":
            self.__cdData['mbId'] = value
        else: 
            raise LibraryException("\"%s\" ist kein valider Parameter" %key)
        return self
    
    """
    Fügt der CD ein Genre hinzu. Der Wert entspricht der ID des Genres in der 
    Datenbank.
    @param key: Der Schlüssel.
    @type key: int
    """        
    def addGenre(self, genre):
        if genre not in self.__genres and isinstance(genre, int):
            self.__genres.append(genre)
    
    """
    Prüft, ob die CD einem entsprechenden Genre zugeordnet ist.
    @param key: Der Schlüssel.
    @type key: int
    @return: Wahr/Falsch
    @rtype: boolean
    """       
    def hasGenre(self, genre):
        return genre in self.__genres
    
    """
    Getter
    @return: Alle CD-Daten.
    @rtype: Dictionary
    """    
    def getData(self):
        return self.__cdData
    
    """
    Getter.
    @return: Die ID der CD in der Datenbank.
    @rtype: int
    """
    def getId(self):
        return self.__cdData['id']
    
    """
    Getter.
    @return: Der Name der CD in der Datenbank.
    @rtype: String
    """
    def getName(self):
        return self.__cdData['name']
    
    """
    Getter.
    @return: Die ID des Artists in der Datenbank.
    @rtype: int
    """    
    def getArtist(self):
        return self.__cdData['artist']
    
    """
    Getter.
    @return: Das Erscheinungsjahr der CD.
    @rtype: int
    """    
    def getYear(self):
        return self.__cdData['year']
    
    """
    Getter.
    @return: Der Pfad zur Bilddatei, welche zur CD gehört.
    @rtype: String
    """    
    def getImgPath(self):
        return self.__cdData['imgPath']
    
    """
    Getter.
    @return: Die MusicBrainz-Id der CD.
    @rtype: String
    """    
    def getMbId(self):
        return self.__cdData['mbId']
    
    """
    Getter.
    @return: Die Genres der CD.
    @rtype: Array
    """    
    def getGenres(self):
        return self.__genres
        
    """
    ----------------------------------------------------------------------------
    Methoden der Klasse
    ----------------------------------------------------------------------------
    """
    
    """
    Liest die CD-Daten aus der Datenbank.
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Track
    """
    def getDataFromDb(self):
        db = Database()
        if (self.__cdData['name'] is not None 
        and self.__cdData['artist'] is not None):
            arguments = {
                'name'   : self.__cdData['name'],
                'artist' : self.__cdData['artist']
            }
        elif self.__cdData['id'] is not None:
            arguments = {'id' : self.__cdData['id']}
        else: 
            raise LibraryException('Keine ID bzw. kein Name+Artist übergeben')      
            
        try: 
            db.select('*', 'Cd', arguments)
            curCd = db.dbCursor.fetchone()
            self.__cdData['id'] = curCd[0]
            self.__cdData['name'] = curCd[1]
            self.__cdData['artist'] = curCd[2]
            self.__cdData['year'] = curCd[3]
            self.__cdData['imgPath'] = curCd[4]
            self.__cdData['mbId'] = curCd[5]
            db.select("*", 'hasGenre', {'cd':self.__cdData['id']})
            for genre in db.dbCursor:
                self.addGenre(int(genre[1]))
        except Exception:
            raise LibraryException('CD nicht vorhanden')
        return self
    
    """
    Speichert die CD-Daten in der Datenbank.
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Track
    """   
    def insertIntoDb(self):
        if (self.__cdData['name'] is not None 
        and self.__cdData['artist'] is not None):                 
            db = Database()
            db.savepoint("sp")
            try:
                db.insert('Cd', {
                    'name'      : self.__cdData['name'],
                    'artist'    : self.__cdData['artist'],
                    'year'      : self.__cdData['year'],
                    'imgPath'   : self.__cdData['imgPath'],
                    'mbId'      : self.__cdData['mbId']
                })
                self.__cdData['id'] = db.dbCursor.lastrowid
                if len(self.__genres) > 0:
                    for genre in self.__genres:
                        db.insert('hasGenre', {
                            'cd':self.__cdData['id'],'genre':genre
                        })
                self.getDataFromDb()
            except Exception:
                db.rollback("sp")
                raise LibraryException('Konnte Daten nicht einfügen')
        else: 
            raise LibraryException('Kein Name+Artist übergeben')
        return self
        
    """
    Löscht eine CD aus der Datenbank.
    ACHTUNG: Hierbei werden auch alle zugehörigen Tracks gelöscht!
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Cd
    """    
    def deleteFromDb(self):
        if self.__cdData['id'] is None:
            self.getDataFromDb()
        db = Database()        
        try: 
            db.delete('Track', {'cd':self.__cdData['id']})
            db.delete('hasGenre', {'cd':self.__cdData['id']})
            db.delete('Cd', {'id':self.__cdData['id']})
        except: raise LibraryException('Artist nicht vorhanden')
        return self
        
    """
    Holt alle Tracks einer CD. Die Sortierungs-Reihenfolge kann über den 
    Parameter orderBy angegeben werden. Dabei kann dieser allen Attributen eines
    C(Track)-Objektes entsprechen.
    @param orderBy: Sortieren nach x.
    @type orderBy: String
    @return: Ein Array mit allen Tracks der CD als Track-Objekte.
    @rtype: Array
    """   
    def getCdsTracks(self, orderBy = 'trackOnCd'):
        self.getDataFromDb()
        db = Database()            
        try:            
            db.select('id', 'Track', {
                'artist' : self.__cdData['artist'], 
                'cd' : self.__cdData['id']
            }, "ORDER BY %s" %(orderBy))
            allTracks = db.dbCursor.fetchall()
            trackArray = []
            for track in allTracks: trackArray.append(Track(track[0]))
            return trackArray
        except: raise LibraryException('CD nicht vorhanden')
